13. Funzioni

Definizione e dichiarazione di una funzione

Le funzioni sono un blocco di codice che assolvono un determinato compito, a cui viene dato un nome specifico ed unico.

Esse possono ricevere o meno dei valori in entrata chiamati parametri, per produrre e restituire o meno un singolo valore.

Il loro principale compito è quello di rendere il codice non solo più leggibile, ma anche più pulito, elastico e flessibile.
Questo è possibile proprio perchè, racchiudendo una porzione di codice all'interno delle nostre funzioni, sarà possibile richiamare quel codice senza doverlo riscrivere, e lo possiamo inoltre rendere adattabile a seconda dei parametri ricevuti in entrata.

Un altro punto di forza si riscontra in fase di Debug (correzione degli errori), in quanto per il medesimo motivo sopracitato, è sufficiente correggere l'errore nella nostra funzione, per far sì che automaticamente abbia effetto ogni volta che viene usato il codice della funzione attraverso una chiamata ad essa.

Vediamo ora come è possibile dichiarare e definire una nuova funzione.
Innanzitutto è necessaria la parola chiave function, a seguire il nome che abbiamo scelto per la nostra funzione, inoltre una lista di parametri racchiusi fra parentesi tonde e separati da una virgola, e infine il corpo della funzione (codice) racchiuso fra parentesi graffe.

function nomefunzione($parametro1, $parametro2) // Da zero a N parametri
{
	// corpo della funzione
}


Restituzione di valori

Molto spesso torna utile che la nuova funzione restituisca un valore per fare in modo che questo venga letto ed utilizzato, come ad esempio il risultato di una operazione matematica o ancora il successo/fallimento di una determinata operazione.

Per restituire un valore, è sufficiente usare la parola chiave return seguita dal valore che deve essere restituito (variabili, costanti, espressioni booleane ...) :

function addizione($valore1, $valore2)
{ return $valore1 + $valore2; }

function inviaEmail($mittente, $destinatario, $oggetto, $messaggio)
{
	// codice per l'invio dell'email
	// return true; (Se l'email viene inviata con successo)
	// return false; (Se l'email non viene inviata con successo)
}


Visibilità delle funzioni

E' possibile richiamare le funzioni in ogni parte del codice, all'interno di altre funzioni, nel corpo principale dello script ecc ...
Per farlo è necessario scrivere il nome della funzione seguita dalle parentesi tonde. Se la funzione riceve dei parametri per cui non sono stati specificati dei valori di default, allora è obbligatorio inserirli all'interno delle parentesi tonde separandoli anche qui da una virgola e chiudendo la riga con un punto e virgola.

echo addizione(5, 4); // Stampa : 9

Come potete notare dall'esempio, è possibile utilizzare i valori ritornati da una funzione proprio come una variabile, stampandoli direttamente con echo, passandoli ad altre funzioni, assegnandoli a variabili e così via. Di seguito alcuni esempi :

function add($n1, $n2) { return intval($n1 + $n2); } // Somma i 2 valori e ritorna il risultato come numero intero
function sub($n1, $n2) { return intval($n1 - $n2); } // Sottrae i 2 valori e ritorna il risultato come numero intero

function pariDispari($num)
{ return (!($num % 2)) ? "pari" : "dispari"; }

$n = sub(17, 12);
echo sub(add(3, 4), $n); // Stampa : 2

$value = pariDispari(3) or die("E' richiesto un numero pari!");
echo "<br />" . $value; // Va a capo nell'output HTML e stampa : "dispari"

Le funzioni in PHP hanno visibilità globale, possono quindi essere richiamate in ogni parte del codice usando il nome della funzione che è Case-Insensitive, anche se vi consiglio di richiamare le funzioni con lo stesso identico nome con cui le avete dichiarate.

PHP fra l'altro, non supporta l'overloading delle funzioni come ad esempio il C++, questo significa che non potete ridefinire una funzione già dichiarata.



Funzioni dentro funzioni

Tornando al discorso della visibilità delle funzioni, è possibile precludere l'utilizzo di alcune funzioni fino all'avvenuta esecuzione di un'altra determinata funzione, dichiarando all'interno di quest'ultima, le funzioni che dovranno essere visibili all'esecuzione di questa.

function func1()
{
	function func2()
	{ echo "Sono la func2()!"; }
}

func1();
func2(); // Stampa : "Sono la func2()!"

Omettendo la chiamata alla funzione func1() si ottiene il seguente errore :
Fatal error: Call to undefined function func2() in C:\AppServ\www\test.php on line X.



Funzioni condizionali

Un altro modo per rendere disponibile una funzione solo in determinati casi, è quello di costruire una funzione condizionale, ossia una funzione dichiarata e definita all'interno di una struttura di controllo come la IF :

$creafunzione = true;

if ($creafunzione)
{
	function funzione()
	{ return "ciao"; }
}

if ($creafunzione) funzione(); // Stampa : "ciao" nel caso in cui $creafunzione sia true

In questi casi è necessario che la dichiarazione della funzione condizionale, appaia nello script prima di una qualunque eventuale chiamata, prerequisito non necessario per le funzioni normali.



Parametri di default

Approfondiremo ora il discorso dei parametri (o argomenti) che le nostre funzioni prenderanno in input.
E' possibile specificare un valore di default, che i parametri della nostra funzione dovranno assumere qualora non venissero specificati.

Per farlo è sufficiente assegnare un valore al parametro durante la dichiarazione della funzione, mediante l'operatore di assegnazione =.
Fate attenzione però all'ordine con cui disponete i parametri, avendo cura di lasciare per ultimi tutti quelli per cui avete previsto un valore di default.

function funzione($par1, $par2, $par3 = "par3", $par4 = "par4")
{
	static $call = 0;

	echo "Chiamata : " . ++$call . "\n<br />\n";

	echo $par1 . "<br />";
	echo $par2 . "<br />";
	echo $par3 . "<br />";
	echo $par4 . "<br /><br />";
}

funzione("pippo", "pluto", "paperino");
funzione("minnie", "topolino");
funzione("crono", "athena", "poseidone", "zeus");
funzione("gastone");

La nostra funzione nell'esempio soprastante, prevede quattro parametri, due dei quali hanno un valore di default.
Nella prima chiamata a funzione() risulta mancante il quarto parametro, la funzione lo sostituisce quindi con la stringa di default "par4".
Nella seconda chiamata mancano il terzo e il quarto parametro e vengono rispettivamente rimpiazzati coi valori "par3" e "par4".
Nella terza chiamata a funzione() invece, vengono specificati tutti e quattro i parametri previsti.
Infine nella quarta ed ultima chiamata viene generato un "Warning" (avvertenza) che segnala la mancanza del secondo parametro, producendo in output solo i parametri uno, tre e quattro.

Questo è il risultato.



Passaggio di parametri per riferimento

Di default PHP passa i parametri alle funzioni per valore, ossia ogni volta che una funzione riceve un parametro, riceve in realtà una copia di esso. Vedremo ora come è possibile invece passare un riferimento alla variabile che contiene il suddetto valore.

Questo metodo si può applicare anche ai valori restituiti dalla funzione, e può tornare utile per svariati motivi come ad esempio il risparmio di memoria o altre metodologie di programmazione più sofisticate che non sono argomento di questa guida.

function funzione(&$stringa, $carattere, $ripetizioni)
{
	$tmp = "";
	
	for ($i = 0; $i < intval($ripetizioni); $i++)
	    $tmp .= $carattere{0};

	$tmp .= $stringa;

    for ($i = 0; $i < intval($ripetizioni); $i++)
	    $tmp .= $carattere{0};

	$stringa = $tmp;
}

$stringa = "Argomenti per riferimento";
funzione($stringa, "*", 10);
echo $stringa; // Stampa : **********Argomenti per riferimento**********

Nell'esempio soprastante, funzione() prende il parametro $stringa per riferimento, grazie alla E commerciale (&) anteposta al nome del parametro, permettondogli di modificare direttamente $stringa, senza necessità di restituire il valore prodotto.



Restituzione di valori per riferimento

E' possibile inoltre far si che una funzione restituisca non una copia di un valore ma ancora un riferimento, anteponendo stavolta la E commerciale (&) al nome della funzione, e avendo cura di usare l'operatore di assegnazione per riferimento =& in questo modo :

function &funzione()
{
	static $contatore = 0;
	return ++$contatore;
}

echo funzione(); // Stampa : 1
echo funzione(); // Stampa : 2
echo funzione(); // Stampa : 3

$value =& funzione();
$value = 0;

echo funzione(); // Stampa : 1

Questo metodo torna spesso utile in quanto, le variabili dichiarate all'interno della funzione, hanno una visibilità confinata alla sola funzione, rendendole quindi inaccessibili all'esterno.



Variabili statiche

Normalmente le variabili dichiarate nelle funzioni, vengono create ad ogni chiamata e distrutte alla fine di ogni esecuzione della funzione, ad eccezione delle variabili statiche.

Anteponendo la parola chiave static al nome della variabile, si indica a PHP di non distruggere la variabile ogni volta che termina una chiamata alla funzione, ma bensì di renderla sempre disponibile fino alla terminazione dell'intero script.

La visibilità delle variabili statiche resta comunque limitata alla funzione, non accessibile quindi a livello globale a meno di restituirla per riferimento come nell'esempio precedente.

Le funzioni possono restituire solo un valore, ma vi capiterà senz'altro di costruire applicazioni con funzioni che dovranno restituire risultati più elaborati, composti da insiemi più complessi di valori.

In questi casi sarà buona cosa progettare le vostre funzioni per organizzare le collezioni di valori da restituire in Array o Oggetti in questo modo :

function ribalta($par1, $par2, $par3)
{ return array($par3, $par2, $par1); }

$array = ribalta("uno", "due", "tre");

for ($i = 0; $i < count($array); $i++)
	echo $array[$i] . " ";

L'esempio produce questo risultato.



Numero di argomenti variabile

Vi potrà capitare di progettare una funzione, senza sapere effettivamente quanti parametri prenderà in input, non potendo quindi ricorrere allo stratagemma dei valori di default descritto precedentemente.

PHP ci mette a disposizione tre funzioni per far fronte a questo tipo di esigenza :

  • func_num_args() - Restituisce un numero intero corrispondente al numero di parametri ricevuto dalla funzione.
  • func_get_arg() - Restituisce il valore che risiede all'indice specificato nell'array dei parametri.
  • func_get_args() - Restituisce un array contenente tutti i parametri ricevuti in ingresso.
function funzione()
{
	$num = func_num_args();
	$parametri = func_get_args();

	$tmp = ($num > 0) ? func_get_arg(0) : 0;

	for ($i = 1; $i < $num; $i++)
		$tmp += $parametri[$i];

	return $tmp;
}

echo funzione(5, 3, 44, 12); // Stampa : 64


Funzioni Variabili

Vedremo ora il concetto delle funzioni variabili, che ci consentirà di chiamare più funzioni usando una sola variabile come riferimento, rendendo il nostro codice non solo più flessibile e di facile modifica, ma permettendoci inoltre di chiamare funzioni di cui non conosciamo a priori il nome.

Il funzionamento è piuttosto semplice, è sufficiente assegnare il nome della funzione che si intende chiamare ad una variabile, ed usare quest'ultima per effettuare la chiamata :

$language = "italiano";

function ilSaluto()
{ return "ciao"; }

function itGreets()
{ return "hello"; }

function ilSalue()
{ return "bonjour "; }

function error()
{ return "error"; }

switch ($language)
{
	case "italiano" : $funzione = "ilSaluto"; break;
	case "english" : $funzione = "itGreets"; break;
	case "french" : $funzione = "ilSalue"; break;
	default : $funzione = "error";
}

echo $funzione(); // Stampa : "ciao"

L'esempio non rispecchia un caso pratico, ma vuole solo mostrare la sintassi per un corretto utilizzo delle funzioni variabili.
Ricordatevi che con questo metodo non potrete effettuare chiamate ai costrutti del linguaggio come echo.



Conclusione

Finiamo il capitolo sulle funzioni, con la segnalazione del metodo function_exists(), che ci consentirà di verificare in fase di runtime, se una funzione è stata dichiarata e quindi esiste :

function funzione() { return "ciao"; }

if (function_exists("funzione")) echo "funzione esiste";
else echo "funzione non esiste";
// Verrà stampato "funzione esiste"